//=============================================================================
//
//		Copyright (C) 1995, 1996 by Paul S. McCarthy and Eric Sunshine.
//				Written by Paul S. McCarthy and Eric Sunshine.
//							All Rights Reserved.
//
//		This notice may not be removed from this source code.
//
//		This object is included in the MiscKit by permission from the authors
//		and its use is governed by the MiscKit license, found in the file
//		"License.rtf" in the MiscKit distribution.	Please refer to that file
//		for a list of all applicable permissions and restrictions.
//		
//=============================================================================
//-----------------------------------------------------------------------------
// MiscTableScrollPB.M
//
//		Pasteboard and services support for MiscTableScroll.
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// $Id: MiscTableScrollPB.M,v 1.3 96/01/13 23:44:36 zarnuk Exp $
// $Log:		MiscTableScrollPB.M,v $
//	Revision 1.3  96/01/13	23:44:36  zarnuk
//	Plugged memory leak.
//	All allocations are now done from [self zone].
//	
//	Revision 1.2  95/10/08	16:12:47  zarnuk
//	Cell* --> id.
//	
//	Revision 1.1  95/09/27	12:21:21  zarnuk
//	Initial revision
//	
//-----------------------------------------------------------------------------
#import <misckit/MiscTableScroll.h>

extern "Objective-C" {
#import <appkit/Application.h>
#import <appkit/Cell.h>
#import <appkit/Pasteboard.h>
}

#define MISC_PB_FIELD_SEPARATOR			'\t'
#define MISC_PB_RECORD_TERMINATOR		'\n'
#define MISC_PB_MAX_TYPES				32

@implementation MiscTableScroll(Pasteboard)

//-----------------------------------------------------------------------------
// - sortSel:border:
//-----------------------------------------------------------------------------
- (void) sortSel:(MiscIntList*)sel_list border:(MiscBorderType)b
	{
	[self border:b physicalToVisual:sel_list];
	[sel_list sort];
	[self border:b visualToPhysical:sel_list];
	}



//-----------------------------------------------------------------------------
// - builtinRegisterServicesTypes
//
// FIXME: Deal with these also:
//		writeTypes[*] = NXRTFPboardType
//		writeTypes[*] = NXFontPboardType;
//		writeTypes[*] = NXColorPboardType
//		writeTypes[*] = NXSelectionPboardType
//		writeTypes[*] = NXDataLinkPboardType
//-----------------------------------------------------------------------------
- (void) builtinRegisterServicesTypes
	{
	NXAtom writeTypes[3];
	NXAtom readTypes[1];

	writeTypes[0] = NXTabularTextPboardType;
	writeTypes[1] = NXAsciiPboardType;
	writeTypes[2] = 0;

	readTypes[0] = 0;

	[NXApp registerServicesMenuSendTypes:writeTypes andReturnTypes:readTypes];
	}



//-----------------------------------------------------------------------------
// - registerServicesTypes
//-----------------------------------------------------------------------------
- (void) registerServicesTypes
	{
	if (delegate != 0 &&
		[delegate respondsTo:@selector(tableScrollRegisterServicesTypes:)])
		[delegate tableScrollRegisterServicesTypes:self];

	else if (dataDelegate != 0 &&
		[dataDelegate respondsTo:@selector(tableScrollRegisterServicesTypes:)])
		[dataDelegate tableScrollRegisterServicesTypes:self];

	else
		[self builtinRegisterServicesTypes];
	}



//-----------------------------------------------------------------------------
// - builtinValidRequestorForSendType:andReturnType:
//-----------------------------------------------------------------------------
- builtinValidRequestorForSendType:(NXAtom)t_write
		andReturnType:(NXAtom)t_read
	{
	if (t_read == 0 &&			// We only send stuff, we never take stuff.
		(t_write == NXTabularTextPboardType || t_write == NXAsciiPboardType) &&
		([self hasRowSelection] || [self hasColSelection]))
		return self;

	return [super validRequestorForSendType:t_write andReturnType:t_read];
	}


//-----------------------------------------------------------------------------
// - validRequestorForSendType:andReturnType:
//-----------------------------------------------------------------------------
- validRequestorForSendType:(NXAtom)t_write andReturnType:(NXAtom)t_read
	{
	if (delegate != 0 && [delegate respondsTo:
		@selector(tableScroll:validRequestorForSendType:andReturnType:)])
		return [delegate tableScroll:self
				validRequestorForSendType:t_write andReturnType:t_read];

	if (dataDelegate != 0 && [dataDelegate respondsTo:
		@selector(tableScroll:validRequestorForSendType:andReturnType:)])
		return [dataDelegate tableScroll:self
				validRequestorForSendType:t_write andReturnType:t_read];

	return [self builtinValidRequestorForSendType:t_write
				andReturnType:t_read];
	}


//-----------------------------------------------------------------------------
// - builtinReadSelectionFromPasteboard:
//-----------------------------------------------------------------------------
- builtinReadSelectionFromPasteboard:pboard
	{
	return self;
	}


//-----------------------------------------------------------------------------
// - readSelectionFromPasteboard:
//-----------------------------------------------------------------------------
- readSelectionFromPasteboard:pb
	{
	if (delegate != 0 && [delegate respondsTo:
		@selector(tableScroll:readSelectionFromPasteboard:)])
		return [delegate tableScroll:self readSelectionFromPasteboard:pb];

	if (dataDelegate != 0 && [dataDelegate respondsTo:
		@selector(tableScroll:readSelectionFromPasteboard:)])
		return [dataDelegate tableScroll:self readSelectionFromPasteboard:pb];

	return [self builtinReadSelectionFromPasteboard:pb];
	}


//-----------------------------------------------------------------------------
// - builtinCanWritePboardType:
//-----------------------------------------------------------------------------
- (BOOL) builtinCanWritePboardType:(NXAtom)type
	{
	return type == NXAsciiPboardType || type == NXTabularTextPboardType;
	}


//-----------------------------------------------------------------------------
// - canWritePboardType:
//-----------------------------------------------------------------------------
- (BOOL) canWritePboardType:(NXAtom)type
	{
	if (delegate != 0 &&
		[delegate respondsTo:@selector(tableScroll:canWritePboardType:)])
		return [delegate tableScroll:self canWritePboardType:type];

	if (dataDelegate != 0 &&
		[dataDelegate respondsTo:@selector(tableScroll:canWritePboardType:)])
		return [dataDelegate tableScroll:self canWritePboardType:type];

	return [self builtinCanWritePboardType:type];
	}


//-----------------------------------------------------------------------------
// - writeNXAsciiPboardTypeToStream:at::
//-----------------------------------------------------------------------------
- (void) writeNXAsciiPboardTypeToStream:(NXStream*)stream
		at:(int)row :(int)col
	{
	char const* s = 0;
	id cell = [self cellAt:row:col];

	if (cell != 0)
		{
		if ([cell respondsTo:@selector(title)])
			s = [cell title];
		else if ([cell respondsTo:@selector(stringValue)])
			s = [cell stringValue];
		}

	if (s != 0)
		{
		for ( ;	 *s != '\0';  s++)
			{
			int c = *s;
			if (c == MISC_PB_FIELD_SEPARATOR)
				c = ' ';
			NXPutc( stream, c );
			}
		}
	}


//-----------------------------------------------------------------------------
// - writeNXAsciiPboardTypeToStream:
//-----------------------------------------------------------------------------
- (void) writeNXAsciiPboardTypeToStream: (NXStream*) stream
	{
	unsigned int i, i_lim;
	MiscCoord_V j, j_lim;
	MiscCoord_P row, col;
	MiscIntList* sel_list = [[MiscIntList allocFromZone:[self zone]] init];

	if ([self numSelectedRows] > 0)
		{
		[self selectedRows:sel_list];
		[self sortSel:sel_list border:MISC_ROW_BORDER];
		i_lim = [sel_list count];
		j_lim = (MiscCoord_V) [self numCols];
		for (i = 0;	 i < i_lim;	 i++)
			{
			row = (MiscCoord_P) [sel_list intAt:i];
			for (j = 0;	 j < j_lim;	 j++)
				{
				if (j > 0) NXPutc( stream, MISC_PB_FIELD_SEPARATOR );
				col = [self colAtPosition:j];
				[self writeNXAsciiPboardTypeToStream:stream at:row:col];
				}
			NXPutc( stream, MISC_PB_RECORD_TERMINATOR );
			}
		}
	else if ([self numSelectedCols] > 0)
		{
		[self selectedCols:sel_list];
		[self sortSel:sel_list border:MISC_COL_BORDER];
		i_lim = [sel_list count];
		j_lim = (MiscCoord_V) [self numRows];
		for (j = 0;	 j < j_lim;	 j++)
			{
			row = [self rowAtPosition:j];
			for (i = 0;	 i < i_lim;	 i++)
				{
				if (i > 0) NXPutc( stream, MISC_PB_FIELD_SEPARATOR );
				col = (MiscCoord_P) [sel_list intAt:i];
				[self writeNXAsciiPboardTypeToStream:stream at:row:col];
				}
			NXPutc( stream, MISC_PB_RECORD_TERMINATOR );
			}
		}

	[sel_list free];
	}


//-----------------------------------------------------------------------------
// - writeNXTabularTextPboardTypeToStream:
//-----------------------------------------------------------------------------
- (void) writeNXTabularTextPboardTypeToStream: (NXStream*) stream
	{
	[self writeNXAsciiPboardTypeToStream:stream];
	}


//-----------------------------------------------------------------------------
// - builtinWritePboard:type:toStream:
//-----------------------------------------------------------------------------
- (void) builtinWritePboard:pb type:(NXAtom)type toStream:(NXStream*)stream
	{
	if (type == NXAsciiPboardType)
		[self writeNXAsciiPboardTypeToStream:stream];
	else if (type == NXTabularTextPboardType)
		[self writeNXTabularTextPboardTypeToStream:stream];
	}


//-----------------------------------------------------------------------------
// - writePboard:type:toStream:
//-----------------------------------------------------------------------------
- (void) writePboard:pb type:(NXAtom)t toStream:(NXStream*)s
	{
	if (delegate != 0 && [delegate respondsTo:
		@selector(tableScroll:writePboard:type:toStream:)])
		[delegate tableScroll:self writePboard:pb type:t toStream:s];

	else if (dataDelegate != 0 && [dataDelegate respondsTo:
		@selector(tableScroll:writePboard:type:toStream:)])
		[dataDelegate tableScroll:self writePboard:pb type:t toStream:s];
	else
		[self builtinWritePboard:pb type:t toStream:s];
	}


//-----------------------------------------------------------------------------
// - builtinWriteSelectionToPasteboard:types:
//-----------------------------------------------------------------------------
- (BOOL) builtinWriteSelectionToPasteboard:pboard
		types:(NXAtom*)original_types
	{
	BOOL result = NO;
	NXAtom types[ MISC_PB_MAX_TYPES + 1 ];
	int nTypes = 0;
	NXAtom const* tp;

	if (original_types != 0)
		for (tp = original_types;  *tp != 0;  tp++)
			if ([self canWritePboardType:*tp])
				if (nTypes < MISC_PB_MAX_TYPES)
					types[ nTypes++ ] = *tp;

	types[ nTypes ] = 0;

	if (nTypes > 0 && ([self hasRowSelection] || [self hasColSelection]))
		{
		int i = 0;

		[pboard declareTypes:types num:nTypes owner:0];

		for (i = 0;	 i < nTypes;  i++)
			{
			NXStream* stream = NXOpenMemory( 0, 0, NX_READWRITE );
			[self writePboard:pboard type:types[i] toStream:stream];
			NXSeek( stream, 0, NX_FROMSTART );
			[pboard writeType:types[i] fromStream:stream];
			NXCloseMemory( stream, NX_FREEBUFFER );
			}

		result = YES;
		}

	return result;
	}


//-----------------------------------------------------------------------------
// - writeSelectionToPasteboard:types:
//-----------------------------------------------------------------------------
- (BOOL) writeSelectionToPasteboard:pboard types:(NXAtom*)types
	{
	if (delegate != 0 && [delegate respondsTo:
		@selector(tableScroll:writeSelectionToPasteboard:types:)])
		return [delegate tableScroll:self
				writeSelectionToPasteboard:pboard types:types];

	if (dataDelegate != 0 && [dataDelegate respondsTo:
		@selector(tableScroll:writeSelectionToPasteboard:types:)])
		return [dataDelegate tableScroll:self
				writeSelectionToPasteboard:pboard types:types];

	return [self builtinWriteSelectionToPasteboard:pboard types:types];
	}


//-----------------------------------------------------------------------------
// - copy:
//-----------------------------------------------------------------------------
- copy:sender
	{
	NXAtom types[3];
	types[0] = NXTabularTextPboardType;
	types[1] = NXAsciiPboardType;
	types[2] = 0;
	[self writeSelectionToPasteboard:[Pasteboard new] types:types];
	return self;
	}



//-----------------------------------------------------------------------------
// - cut:
//-----------------------------------------------------------------------------
- cut:sender
	{
	return [self copy:sender];
	}

@end
